import asyncio
import json
from typing import Dict, Any, Optional

from langchain_core.messages import HumanMessage, AIMessage
from langgraph.constants import END
from langgraph.graph import add_messages

from app.models import SessionState, CustomEncoder
from app.utils.llm_client import LLMClient
from app.utils.logger_util import user_logger


class InputType:
    REQUIREMENT = "requirement"
    ISSUE = "issue"


message_str = '''{
	"type": "",
	"message": 
		{
			"desc": "",
			"data": ""	
		}
    }'''


def classify_user_input_node(state: SessionState, config: dict) -> SessionState:
    new_state = state.copy()
    # 从反转的消息列表中筛选用户消息，取第一个（即最新的用户消息），如果没有用户消息则为None

    thread_id = config.get("configurable", {}).get("thread_id")

    # 将JSON字符串转换为Python字典
    message_dict = json.loads(message_str)
    message_dict["type"] = "节点"
    message_dict["message"]["desc"] = "需求类型界定"
    #message_dict["message"]["data"] = json.dumps(state,  cls=CustomEncoder,ensure_ascii=False)
    message_dict["message"]["data"] = "*首先深度沟通，精准拆解数据需求，明确分析方向与核心目标；接着依托专业数据资源，执行精准的数据查询，筛选高质量数据源；最后整合查询结果，形成贴合需求的分析结论，助力你快速获取有价值的数据支撑，高效解决数据相关问题：" + str(state)
    user_logger.info(thread_id, json.dumps(message_dict, ensure_ascii=False))
    user_input = next((msg.content for msg in reversed(new_state["messages"]) if isinstance(msg, HumanMessage)), None)

    # 没有用户输入，直接结束
    if user_input is None:
        new_state["messages"] = add_messages(state["messages"], [AIMessage(content="未检测到用户输入，对话结束。")])
        new_state["next"] = END
        return new_state

    try:
        # 调用分类函数，传入带 thread_id 的 LLMClient，以便记录思考日志
        llm_client = LLMClient(thread_id=thread_id)
        classify_result = classify_user_input(user_input, llm_client)

        # 生成并记录思考摘要（适用于无内置reasoning的模型）
        try:
            think_pack = llm_client.generate_think_sync(
                purpose="输入分类理由",
                context={
                    "user_input": user_input,
                    "classification": classify_result
                },
                max_tokens=200,
            )
            think_text = think_pack.get("display") if isinstance(think_pack, dict) else str(think_pack)
        except Exception:
            think_text = None
        sentence_type = classify_result["type"]
        message_dict["type"] = "思考"
        if think_text:
            message_dict["message"]["desc"] = think_text
        else:
            message_dict["message"]["desc"] = "分类摘要生成失败"
        message_dict["message"]["data"] = "当前分类结果为" + sentence_type
        user_logger.info(thread_id, json.dumps(message_dict, ensure_ascii=False))
        if sentence_type == "issue":
            # 陈述句：结束对话
            end_msg = "您输入的是一个问题，对话暂时结束。"
            new_state["messages"] = add_messages(state["messages"], [AIMessage(content=end_msg)])
            new_state["next"] = END

        else:
            #
            end_msg = "您输入的是一个需求，我将调用check_information来进行需求检查。"
            new_state["messages"] = add_messages(state["messages"], [AIMessage(content=end_msg)])
            new_state["next"] = "require_clear_or_not"

        plan_txt = generate_plan_with_llm(user_input)
        print(plan_txt)
        message_dict["type"] = "规划"
        message_dict["message"]["desc"] = "大模型规划: " + str(plan_txt)
        message_dict["message"]["data"] = None
        user_logger.info(thread_id, json.dumps(message_dict, ensure_ascii=False))


    except Exception as e:
        print(f"处理出错: {e}")
        new_state["messages"] = add_messages(state["messages"], [AIMessage(content="处理出错，对话结束。")])
        new_state["next"] = END

    return new_state


def classify_user_input(user_input: str, llm_client: Optional[LLMClient] = None) -> Dict[str, Any]:
    """
    分类用户输入，判断是问题还是需求

    Args:
        user_input: 用户输入的文本
        llm_client: LLM客户端实例

    Output:
    {
        "type": "requirement/issue/unclear",
        "confidence": 0.95,
        "reason": "判断理由",
        "keywords": ["关键词1", "关键词2"]
    }
    """
    if llm_client is None:
        llm_client = LLMClient()

    # 构建系统提示
    system_prompt = """你是一个智能分类助手，需要判断用户输入的是"问题"还是"需求"。

分类标准：
- 问题(issue)：描述当前遇到的困难、错误、故障或异常情况，需要解决的问题
- 需求(requirement)：描述想要实现的功能、目标或期望，需要开发或改进的内容

请严格按照以下JSON格式回复：
{
    "type": "issue或requirement",
    "confidence": 0.0-1.0之间的置信度,
    "reason": "简短的判断理由",
    "keywords": ["提取的关键词列表"]
}

示例：
输入："登录页面报错，无法正常登录"
输出：{"type": "issue", "confidence": 0.9, "reason": "描述了登录报错的问题", "keywords": ["登录", "报错", "无法"]}

输入："需要一个用户管理系统"
输出：{"type": "requirement", "confidence": 0.9, "reason": "描述了需要开发的功能", "keywords": ["用户管理系统", "需要"]}"""

    # 构建用户提示
    user_prompt = f"请分类以下用户输入：\n{user_input}"

    try:
        # 调用LLM进行分类
        result = asyncio.run(llm_client.simple_chat(user_prompt, system_prompt))

        # 尝试解析JSON结果
        import json
        try:
            parsed_result = json.loads(result)
            return parsed_result
        except json.JSONDecodeError:
            # 如果解析失败，返回默认结果
            return {
                "type": "unclear",
                "confidence": 0.0,
                "reason": "LLM返回格式错误",
                "keywords": []
            }

    except Exception as e:
        # 如果调用LLM失败，返回错误结果
        return {
            "type": "unclear",
            "confidence": 0.0,
            "reason": f"LLM调用失败: {str(e)}",
            "keywords": []
        }

def generate_plan_with_llm(user_input: str, llm_client: Optional[LLMClient] = None) :
    """
    模拟agent规划模式


    """
    if llm_client is None:
        llm_client = LLMClient()

    # 构建系统提示
    system_prompt = """
    你是一个流程表述生成器。  
任务：基于用户输入，生成一段自然语言“伪规划说明”，要求：
1. 不做真实规划，只是自然语言串联。
2. 必须包含以下逻辑顺序：
   - 已接收任务/输入
   - 调用“问题-需求分析模块”并进行判定
   - 如果是需求，调用“需求澄清模块”，提取关键信息
   - 将关键信息交给分析匹配节点
   - 如果用户不满足，会进行多轮交互
   - 最终产出报告
3. 每次生成的语句要有差异，可以用不同的词语、连接词、句式。
4. 输出只保留最终生成的完整表述，不要附加解释。"""

    # 构建用户提示
    user_prompt = f"以下是用户输入：\n{user_input}"
    result = asyncio.run(llm_client.simple_chat(user_prompt, system_prompt))

    return result